import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:share_fit/app/controllers/base/base_sports_controller.dart';
import 'package:share_fit/app/controllers/home/exercise_records/model/exercise_type.dart';
import 'package:share_fit/app/helper/ext/tr_ext.dart';
import 'package:share_fit/app/models/home/workout_model.dart';
import 'package:share_fit/app/models/sports/sport_detail_data.dart';
import 'package:share_fit/app/models/sports/sport_gps_data.dart';
import 'package:share_fit/app/tools/date_tool.dart';
import 'package:share_fit/app/tools/unit_util.dart';
import 'package:share_fit/app/ute/uteped_const.dart';
import 'package:share_fit/generated/locales.g.dart';

import 'state.dart';

class MotionLogic extends BaseSportsController {
  final MotionState state = MotionState();

  /// 实时定位
  StreamSubscription<Position>? positionStream;

  Position? _currentPosition;

  GoogleMapController? googleMapController;

  Timer? locationTimer;

  var realTimeData = 'realTimeData';

  void gpsSignal(int signal) {
    state.signal = signal;
    update(['gps_signal']);
  }

  void showMap(bool show) {
    state.isShowMap = show;
    update(['show_map']);
  }

  void isPause(bool isPause) {
    state.isPause = isPause;

    if (isPause) {
      uTEPedSports.pause();
      if (positionStream != null) {
        positionStream!.pause();
      }
    } else {
      uTEPedSports.resume();
      if (positionStream != null) {
        positionStream!.resume();
      }
    }

    update(['sport_state']);
  }

  void isLock(bool isLock) {
    state.isLock = isLock;
    update(['sport_state']);
  }

  void setProgress() {
    update(['unlock_progress']);
  }

  @override
  String getRemotePath() {
    return UTEPedConst.pathSports;
  }

  @override
  String getStoragePath() {
    return UTEPedConst.pathSports;
  }

  @override
  void onClose() {
    super.onClose();
    uTEPedSports.cancelLocation(positionStream);
    googleMapController?.dispose();
    locationTimer?.cancel();
  }

  @override
  void initState() {
    vRemoteReqAsync(UTEPedConst.methodStartGpsSignal, {});
  }

  @override
  void onRemoteEvent(event, method) {
    Map value = event[UTEPedConst.keyValue];
    switch (method) {
      case UTEPedConst.methodSetDeviceOperator:
        uTEPedSports.onUpdateSportState(value);
        state.isPause = uTEPedSports.sportState.isPause();
        update(['sport_state']);
        break;
      case UTEPedConst.methodSetWorkoutRealTimeData:
        setDistance(value);
        setAltitude(value);
        uTEPedSports.onSetWorkoutRealTimeData(value);
        update([realTimeData]);
        _saveData(value);
        break;
      case UTEPedConst.methodSetSportOneRecord: // 手表上报的运动数据
        uTEPedSports.onSaveExerciseRecord(value, state.gpsDataList, state.detailDataList, state.strideList);
        break;
      case UTEPedConst.methodStartGpsSignal:
        updateGpsSignal(value);
        break;
      default:
        break;
    }
  }

  /// 骑行运动不会上报距离，需要app自行计算
  setDistance(Map realTimeData) {
    if (state.goalInfo['workoutType'] == 2 && state.gpsDataList.isNotEmpty && _currentPosition != null) {
      LatLng start = state.gpsDataList.last.toLatLng();
      int distance = realTimeData['distance'];
      distance += Geolocator.distanceBetween(start.latitude, start.longitude, _currentPosition!.latitude, _currentPosition!.longitude) ~/ 10;
      Fluttertoast.showToast(msg: _currentPosition.toString(), gravity: ToastGravity.TOP);
      realTimeData['distance'] = distance;
    }
  }

  setAltitude(Map realTimeData) {
    if (realTimeData['altitude'] == null || realTimeData['altitude'] == 0) {
      realTimeData['altitude'] = _currentPosition == null ? 0 : _currentPosition!.altitude.toInt();
    }
  }

  _saveData(Map map) {
    SportDetailData sdd = SportDetailData();
    if (sdd.from(map)) {
      state.detailDataList.add(sdd);
    }

    if (map['stride'] != null && map['stride'] > 0) {
      state.strideList.add(map['stride']);
    }
  }

  String getGoalInfo() {
    if (state.goalInfo.isNotEmpty) {
      if (state.goalInfo.containsKey('duration') && state.goalInfo['duration'] > 0) {
        return DateTool.second2HMS(state.goalInfo['duration'], isEasy: false);
        // return '${state.goalInfo['duration']} ${LocaleKeys.sports_goal_duration_unit_text.ts}';
      } else if (state.goalInfo.containsKey('distance') && state.goalInfo['distance'] > 0) {
        return '${state.goalInfo['distance']} ${getLengthUnitString()}';
      } else if (state.goalInfo.containsKey('calories') && state.goalInfo['calories'] > 0) {
        return '${state.goalInfo['calories']} ${LocaleKeys.thermal_unit_kcal.ts}';
      } else {
        return '--';
      }
    } else {
      return '--';
    }
  }

  /// 如果两个定位之间的距离大于2米，则认为是后一个定位无效定位
  bool isInvalidPosition(LatLng start, LatLng end) {
    double distance = Geolocator.distanceBetween(start.latitude, start.longitude, end.latitude, end.longitude);
    return distance > 20;
  }

  void drawPolylineOnMap() {
    locationTimer = Timer.periodic(const Duration(seconds: 2), (timer) {
      if (timer.tick > 1) {
        uTEPedSports.getCurrentLocation().then((pos) {
          uTEPedSports.addPolylineToMap(pos, (latLng) {
            // 如果是无效定位则不更新地图轨迹
            if (state.gpsDataList.isNotEmpty && isInvalidPosition(state.gpsDataList.last.toLatLng(), latLng)) return;

            if (!uTEPedSports.sportState.isPause() && !state.gpsDataList.any((e) => e.exists(latLng))) {
              // 更新轨迹
              state.polyLine.points.add(latLng);

              // 保存gps数据
              state.gpsDataList.add(SportGpsData(
                accuracy: pos.accuracy,
                gpsLatitude: latLng.latitude,
                gpsLongitude: latLng.longitude,
              ));

              // 将当前定位保存，以便将海拔数据传给手表
              _currentPosition = pos;
              if (state.gpsDataList.length == 1) {
                updateStartPointMarker(state.gpsDataList.first.toLatLng());
              }

              if (state.gpsDataList.length > 1) {
                updateMovingMarker(state.gpsDataList.last.toLatLng());
                googleMapController?.moveCamera(CameraUpdate.newLatLng(latLng));
              }

              update(['show_map']);
            }
          });
        });
      }
    });
  }

  updateStartPointMarker(LatLng latLng) async {
    BitmapDescriptor startIcon = await BitmapDescriptor.fromAssetImage(
      const ImageConfiguration(),
      Platform.isIOS ? "assets/images/sports/start_point_ios.png" : "assets/images/sports/start_point_android.png",
    );
    state.markers.first = Marker(
      markerId: const MarkerId('start'),
      position: latLng,
      icon: startIcon,
    );
  }

  updateMovingMarker(LatLng latLng) async {
    BitmapDescriptor endIcon = await BitmapDescriptor.fromAssetImage(
      const ImageConfiguration(),
      Platform.isIOS ? "assets/images/sports/start_point_person_ios.png" : "assets/images/sports/start_point_person_android.png",
    );
    state.markers.last = Marker(
      markerId: const MarkerId('end'),
      position: latLng,
      icon: endIcon,
    );
  }

  void updateGpsSignal(signalMap) {
    int signal = signalMap['signal'];
    state.signal = signal;
    update(['gps_signal']);
  }

  onMapCreated(GoogleMapController controller) {
    googleMapController = controller;
    // 重新获取当前定位
    uTEPedSports.getCurrentLocation().then((pos) {
      controller.moveCamera(CameraUpdate.newCameraPosition(CameraPosition(target: LatLng(pos.latitude, pos.longitude), zoom: 17.0)));
    });
  }

  /// 设置运动目标，并且根据运动类型决定是否要显示地图和gps信号
  void setSportsGoalAndDrawRouteLine() {
    if (Get.arguments is Map) {
      state.goalInfo = Get.arguments;
    }

    if (state.goalInfo.isNotEmpty && state.goalInfo.containsKey('workoutType')) {
      bool result = Type.isMotionTrail(state.goalInfo['workoutType']);

      /// 更新地图的可见状态
      showMap(result);

      if (result) {
        drawPolylineOnMap();
      }
    }
  }

  void saveNecessaryParams(WorkoutModel wm) {
    wm.address = getAddress();

    List<SportDetailData> sddList = wm.detailList.map((e) => SportDetailData.fromJson(e)).toList();

    int pace = sddList.isEmpty ? 0 : sddList.map((e) => e.pace ?? 0).reduce((value, element) => value + element);
    wm.pace = sddList.isEmpty ? 0 : pace ~/ sddList.length;

    int heartRate = sddList.isEmpty ? 0 : sddList.map((e) => e.heartRate ?? 0).reduce((value, element) => value + element);
    wm.heart = sddList.isEmpty ? 0 : heartRate ~/ sddList.length;

    // int cadence = sddList.isEmpty ? 0 : sddList.map((e) => e.stepFrequency ?? 0).reduce((value, element) => value + element);
    // wm.stride = sddList.isEmpty ? 0 : cadence ~/ sddList.length;

    int altitude = sddList.isEmpty ? 0 : sddList.map((e) => e.elevation ?? 0).reduce((value, element) => value + element);
    wm.altitude = sddList.isEmpty ? 0 : altitude ~/ sddList.length;

    // 运动结束上报数据中没有步幅字段（注意：value['stride']是手动添加的字段），只能从实时上报数据中收集，再做平均
    wm.stride = state.strideList.isEmpty ? 0 : state.strideList.reduce((value, element) => value + element) ~/ state.strideList.length;
  }

  getRealTimeDistanceText() {
    return uTEPedSports.realTimeData.getRealTimeDistanceText(UnitUtil.getLengthUnit());
  }
}
